namespace RBAC.Read.Api.Application.Handler.BomHandler
{
    using MediatR;
    using Microsoft.Extensions.Logging;
    using NPOI.SS.UserModel;
    using NPOI.XSSF.UserModel;
    using RBAC.Domain.BomManage;
    using RBAC.Interstructrue.Base;
    using RBAC.Read.Api.Application.Command.BomCommand;
    using RBAC.Read.Api.Application.Dto;
    using RBAC.Read.Api.Application.Dto.Bom;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// 根据 BomId 导出 BomItem 节点（树形展示，含序号列）
    /// </summary>
    public class GetBomItemExportByBomIdHandler : IRequestHandler<GetBomItemExportByBomIdCommand, FileExportResult>
    {
        private readonly IBaseRepository<BomItem> bomItemRepository;
        private readonly IBaseRepository<Bom> bomRepository;
        private readonly ILogger<GetBomItemExportByBomIdHandler> logger;

        public GetBomItemExportByBomIdHandler(
            IBaseRepository<BomItem> bomItemRepository,
            IBaseRepository<Bom> bomRepository,
            ILogger<GetBomItemExportByBomIdHandler> logger)
        {
            this.bomItemRepository = bomItemRepository;
            this.bomRepository = bomRepository;
            this.logger = logger;
        }

        public Task<FileExportResult> Handle(GetBomItemExportByBomIdCommand request, CancellationToken cancellationToken)
        {
            var result = new FileExportResult();
            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (request.BomId <= 0)
                {
                    result.FileName = "NOT_FOUND";
                    return Task.FromResult(result);
                }

                var bom = bomRepository.GetFirstOrDefault("Id = @Id AND IsDeleted = 0", new { Id = request.BomId });
                if (bom == null)
                {
                    result.FileName = "NOT_FOUND";
                    return Task.FromResult(result);
                }

                // 读取明细并按 Position、Id 排序
                var items = bomItemRepository.GetAll("BomId = @BomId AND IsDeleted = 0", new { BomId = request.BomId })
                    .OrderBy(x => x.Position ?? int.MaxValue)
                    .ThenBy(x => x.Id)
                    .ToList();

                // 构建树节点
                var nodeMap = items.ToDictionary(
                    x => x.Id,
                    x => new BomItemTreeDto
                    {
                        Id = x.Id,
                        BomId = x.BomId,
                        BomName = x.BomName,
                        ParentId = x.ParentId,
                        MaterialId = x.MaterialId,
                        MaterialName = x.MaterialName,
                        Qty = x.Qty,
                        Position = x.Position,
                        Children = new List<BomItemTreeDto>()
                    });

                var roots = new List<BomItemTreeDto>();
                foreach (var n in nodeMap.Values)
                {
                    if (n.ParentId.HasValue && nodeMap.TryGetValue(n.ParentId.Value, out var parent))
                        parent.Children.Add(n);
                    else
                        roots.Add(n);
                }

                // 定义一个扁平结构用于导出
                var exportRows = new List<(string No, BomItemTreeDto Node)>();

                void Traverse(List<BomItemTreeDto> nodes, string prefix)
                {
                    for (int i = 0; i < nodes.Count; i++)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        // 每层先按 Position、Id 排序
                        var ordered = nodes
                            .OrderBy(x => x.Position ?? int.MaxValue)
                            .ThenBy(x => x.Id)
                            .ToList();
                        // 注意：为了避免重复排序，将当前索引映射到排序后的列表
                        var node = ordered[i];
                        var no = string.IsNullOrEmpty(prefix) ? (i + 1).ToString() : $"{prefix}.{i + 1}";
                        exportRows.Add((no, node));
                        if (node.Children != null && node.Children.Count > 0)
                        {
                            // 递归子节点
                            var childList = node.Children
                                .OrderBy(x => x.Position ?? int.MaxValue)
                                .ThenBy(x => x.Id)
                                .ToList();
                            // 递归时不复用 ordered 引用
                            Traverse(childList, no);
                        }
                    }
                }

                // 从根开始遍历
                roots = roots
                    .OrderBy(x => x.Position ?? int.MaxValue)
                    .ThenBy(x => x.Id)
                    .ToList();
                // 使用 while/for 安全遍历
                for (int i = 0; i < roots.Count; i++)
                {
                    var node = roots[i];
                    var no = (i + 1).ToString();
                    exportRows.Add((no, node));
                    if (node.Children != null && node.Children.Count > 0)
                    {
                        var childList = node.Children
                            .OrderBy(x => x.Position ?? int.MaxValue)
                            .ThenBy(x => x.Id)
                            .ToList();
                        Traverse(childList, no);
                    }
                }

                // 生成 Excel
                using var workbook = new XSSFWorkbook();
                var sheet = workbook.CreateSheet("BOM明细");

                // 表头
                var header = sheet.CreateRow(0);
                header.CreateCell(0).SetCellValue("序号");
                header.CreateCell(1).SetCellValue("物料名称");
                header.CreateCell(2).SetCellValue("用量");
                header.CreateCell(3).SetCellValue("装配顺序");

                for (int r = 0; r < exportRows.Count; r++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var (no, node) = exportRows[r];
                    var row = sheet.CreateRow(r + 1);
                    row.CreateCell(0).SetCellValue(no);
                    row.CreateCell(1).SetCellValue(node.MaterialName ?? string.Empty);
                    row.CreateCell(2).SetCellValue((double)node.Qty);
                    row.CreateCell(3).SetCellValue(node.Position.HasValue ? node.Position.Value : 0);
                }

                for (int c = 0; c <= 3; c++)
                {
                    sheet.AutoSizeColumn(c);
                }

                using var ms = new System.IO.MemoryStream();
                workbook.Write(ms, leaveOpen: true);
                result.Bytes = ms.ToArray();
                result.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                result.FileName = $"{(bom.Name ?? "BOM")}_{System.DateTime.Now:yyyyMMddHHmmss}.xlsx";
            }
            catch (OperationCanceledException)
            {
                logger.LogWarning("BOM明细导出被取消");
                result.Bytes = System.Array.Empty<byte>();
                result.ContentType = "application/octet-stream";
                result.FileName = string.Empty;
            }
            catch (System.Exception ex)
            {
                logger.LogError(ex, "BOM明细导出失败: {Message}", ex.Message);
                result.Bytes = System.Array.Empty<byte>();
                result.ContentType = "application/octet-stream";
                result.FileName = string.Empty;
            }

            return Task.FromResult(result);
        }
    }
}
